package com.un.ebs.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.un.ebs.core.UserContext;
import com.un.ebs.core.common.GroupListInfo;
import com.un.ebs.core.enums.IndustryTypeEnum;
import com.un.ebs.core.enums.PowerTypeEnum;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.exception.BusinessPermissionDeniedException;
import com.un.ebs.core.power.PowerResourceObject;
import com.un.ebs.core.power.PowerResourceSet;
import com.un.ebs.core.util.*;
import com.un.ebs.customer.CustomerConfigureCode;
import com.un.ebs.customer.domain.*;
import com.un.ebs.customer.event.CustomerTraceEvent;
import com.un.ebs.customer.mapper.CustomerDefunctMapper;
import com.un.ebs.customer.service.CustomerService;
import com.un.ebs.customer.service.DefunctService;
import com.un.ebs.memorial.dto.OrderWxPayResponse;
import com.un.ebs.order.OrderConfigureCode;
import com.un.ebs.order.domain.*;
import com.un.ebs.order.dto.*;
import com.un.ebs.order.enums.DeliverTypeEnum;
import com.un.ebs.order.enums.OrderStatusEnum;
import com.un.ebs.order.enums.PaymentStatusEnum;
import com.un.ebs.order.mapper.*;
import com.un.ebs.order.service.OrderExpireService;
import com.un.ebs.order.service.OrderService;
import com.un.ebs.product.domain.*;
import com.un.ebs.product.dto.ProductClassOrderAttrVO;
import com.un.ebs.product.dto.ProductSkuVo;
import com.un.ebs.product.enums.ProductChargeTypeEnum;
import com.un.ebs.product.enums.ProductSkuResourceStatusEnum;
import com.un.ebs.product.enums.ProductUnitTypeEnum;
import com.un.ebs.product.mapper.ProductClassOrderAttrExtMapper;
import com.un.ebs.product.service.ProductClassService;
import com.un.ebs.product.service.ProductService;
import com.un.ebs.product.service.ProductSkuService;
import com.un.ebs.sys.domain.Personnel;
import com.un.ebs.sys.domain.UserExt;
import com.un.ebs.sys.dto.PersonnelDto;
import com.un.ebs.sys.service.*;
import com.un.ebs.workOrder.domain.WorkOrder;
import com.un.ebs.workOrder.dto.WorkOrderAddDto;
import com.un.ebs.workOrder.service.WorkOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Year;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author liubo
 * @since 2019-11-16
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    DelayedQueueService delayedQueueService;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private OrderExtMapper orderExtMapper;

    @Autowired
    private BzOrderMapper bzOrderMapper;

    @Autowired
    private OrderItemExtMapper orderItemExtMapper;

    @Autowired
    private OrderAttrMapper orderAttrMapper;

    @Autowired
    private CustomerDefunctMapper customerDefunctMapper;

    @Autowired
    private ProductClassOrderAttrExtMapper productClassOrderAttrExtMapper;

    @Autowired
    private ProductSkuService productSkuService;

    @Autowired
    private AppPowerService appPowerService;

//    @Autowired
//    private OrderReportExtMapper orderReportExtMapper;

    @Autowired
    private ProductService productService;

    @Autowired
    private ProductClassService productClassService;

    @Autowired
    private UserService userService;

    @Autowired
    private DefunctService defunctService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private WorkOrderService workOrderService;

    @Autowired
    private ConfigureService configureService;

    @Autowired
    private WxService wxService;

    @Autowired
    private PersonnelService personnelService;

    @Autowired
    OrderExpireService orderExpireService;

    @Autowired
    private RedisService redisService;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final String prefix = "order_attr";

    private String makeOrderId() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String orderId = sdf.format(new Date());
        orderId = orderId + String.format("%04d", baseMapper.maxCode());
        return orderId;
    }

    @CacheEvict(cacheNames = {"customer", "spu_order_rec"}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String add(OrderAddDto req) {
        if (StringUtils.isNullOrEmpty(req.getCustId())) {
            throw new BusinessException("客户不能为空。");
        }
        CustomerExt customer = customerService.queryViewById(req.getCustId());
        if (customer == null) {
            throw new BusinessEntityNotFoundException(req.getCustId(), "客户");
        }

        Order obj = new Order();
        obj.setCode(makeOrderId());
        obj.setTraceId(req.getTraceId());
        obj.setCustId(customer.getId());
        obj.setCustName(customer.getName());
        obj.setLinkman(req.getLinkman());
        obj.setLinkmanPhone(req.getLinkmanPhone());
        obj.setLinkmanAdd(req.getLinkmanAdd());
        obj.setTagId(req.getDefunctId());
        obj.setTagRefSkuId(req.getDefunctTombSkuId());
        obj.setRemark(req.getRemark());
        Personnel personnel = personnelService.queryById(req.getPersonnelId(), UserContext.getInstance().getTenantId());
        if (personnel != null) {
            obj.setPersonnelId(req.getPersonnelId());
            obj.setPersonnelName(personnel.getName());
        }
        obj.insert();

        if (!StringUtils.isNullOrEmpty(req.getDefunctId())) {
            LambdaQueryWrapper<CustomerDefunct> lq = Wrappers.lambdaQuery();
            lq.eq(CustomerDefunct::getDefunctId, req.getDefunctId());
            lq.eq(CustomerDefunct::getCustomerId, customer.getId());
            CustomerDefunct objRef = customerDefunctMapper.selectOne(lq);
            if (objRef == null) {
                objRef = new CustomerDefunct();
                objRef.setCustomerId(req.getCustId());
                objRef.setDefunctId(req.getDefunctId());
                objRef.insert();
            }
        }

        for (OrderItemDto dto : req.getItems()) {
            if (dto.getQty() == 0) {
                throw new BusinessException("SKU 数量不能为零！");
            }

            ProductSkuExt sku = productSkuService.queryViewById(dto.getSkuId());

            //销售逻辑检查
            checkCanSale(sku);

            //行业逻辑检查
            if (sku.getIsMustDefunctByOrder() && sku.getIsMustDefunctTombSkuByOrder()) {
                checkAddOrSubmit(obj.getTagId(), sku.getId(), sku, req.getDefunctTombSkuId());
            } else {
                checkAddOrSubmit(obj.getTagId(), sku.getId(), sku, null);
            }

            OrderItem item = new OrderItem();
            item.setSkuId(dto.getSkuId());
            item.setStartTime(dto.getStartTime());
            item.setEndTime(dto.getEndTime());
            item.setRemark(dto.getRemark());
            item.setOrderId(obj.getId());
            item.setDeliverStatus(false);
            item.setDeliverTime(null);
            item.setDeliverUserId(null);
            item.setSkuItemParentId(dto.getSkuItemParentId());
            if (!StringUtils.isNullOrEmpty(dto.getSkuItemId())) {
                ProductSkuItemExt skuItem = productSkuService.queryItemById(dto.getSkuItemId());
                if (skuItem == null) {
                    throw new BusinessException("添加的套餐商品没有找到。");
                }
                item.setSkuItemId(dto.getSkuItemId());
                item.setPrice(0d);
                item.setQty(skuItem.getQty().doubleValue());
                item.setSkuItemParentId(skuItem.getParentId());
            } else {
                item.setPrice(dto.getPrice());
                item.setQty(dto.getQty());
            }
            if (sku.getUnitType() == ProductUnitTypeEnum.ProductQty && dto.getDeliverType() == DeliverTypeEnum.Default) {
                throw new BusinessException("请指定 " + sku.getNameAs() + " 交付方式。");
            } else {
                if (dto.getDeliverType() == DeliverTypeEnum.TransportUserAdd &&
                        StringUtils.isNullOrEmpty(obj.getTagId()) &&
                        UserContext.getInstance().getIndustryType() == IndustryTypeEnum.FuneralAndInterment) {
                    throw new BusinessException(sku.getNameAs() + "的交付类型为" + DeliverTypeEnum.TransportUserAdd.getDesc() + "时，必须指定使用者。");
                }
                item.setDeliverType(dto.getDeliverType().getCode());
            }
            item.insert();
        }
        return obj.getId();
    }

    @CacheEvict(cacheNames = {"customer", "spu_order_rec"}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String addSimple(OrderSimpleAddDto req) {
        List<String> ids = customerService.queryCustIdByUserId(SecurityUtils.getUserContent().getId());
        if (StringUtils.isNullOrEmpty(ids)) {
            throw new BusinessException("您的账号未绑定到客户账号信息。");
        }
        Customer cust = customerService.queryById(ids.get(0));

        Order order = new Order();
        order.setCode(makeOrderId());
        order.setCustId(cust.getId());
        order.setCustName(req.getName());
        order.setLinkman(req.getName());
        order.setLinkmanPhone(req.getPhone());
        order.setLinkmanAdd(req.getAddress());
        order.setIsDelete(false);
        order.setSubmitStatus(true);
        order.setSubmitUserId(SecurityUtils.getUserContent().getId());
        order.setSubmitTime(new Date());
        order.setSubmitUserName(cust.getName());
        order.setRemark(req.getRemark());
        order.insert();

        for (OrderItemBuyDto item : req.getItems()) {
            ProductSkuExt sku = productSkuService.queryViewById(item.getSkuId());
            checkCanSale(sku);

            OrderItem obj = new OrderItem();
            obj.setOrderId(order.getId());
            obj.setSkuId(item.getSkuId());
            obj.setPrice(sku.getPrice());
            obj.setQty(item.getQty());
            obj.setRemark(item.getRemark());
            obj.setDeliverStatus(false);
            obj.setDeliverType(req.getDeliverType().getCode());
            obj.insert();
        }

        return order.getId();
    }

    @Transactional
    @Override
    public void update(OrderUpdateDto req) {
        Order obj = getById(req.getId());
        if (obj.getSubmitStatus() || obj.getAcceptStatus() || obj.getDeliverStatus()) {
            throw new BusinessException("订单不能修改。");
        }
        Personnel personnel = personnelService.queryById(req.getPersonnelId(), UserContext.getInstance().getTenantId());
        if (personnel == null) {
            throw new BusinessException("指定的业务员无效。");
        }

        CustomerExt customer = customerService.queryViewById(req.getCustId());
//        if (!personnel.getId().equals(customer.getPersonnelId())) {
//            throw new BusinessException("客户 [" + customer.getName() + "] 的业务只能由 [" + customer.getPersonnelName() + "] 办理，或者将客户负责人变更为 [" + personnel.getName() + "] 后再办理此业务。");
//        }

        obj.setCustId(req.getCustId());
        obj.setLinkman(req.getLinkman());
        obj.setLinkmanPhone(req.getLinkmanPhone());
        obj.setLinkmanAdd(req.getLinkmanAdd());
        obj.setTagId(req.getDefunctId());
        obj.setTagRefSkuId(req.getDefunctTombSkuId());
        obj.setPersonnelId(req.getPersonnelId());
        obj.setPersonnelName(personnel.getName());
        obj.updateById();

        if (!StringUtils.isNullOrEmpty(req.getDefunctId())) {
            LambdaQueryWrapper<CustomerDefunct> lq = Wrappers.lambdaQuery();
            lq.eq(CustomerDefunct::getCustomerId, req.getCustId());
            lq.eq(CustomerDefunct::getDefunctId, req.getDefunctId());
            CustomerDefunct objRef = customerDefunctMapper.selectOne(lq);
            if (objRef == null) {
                objRef = new CustomerDefunct();
            }
            objRef.setCustomerId(req.getCustId());
            objRef.setDefunctId(req.getDefunctId());
            objRef.insertOrUpdate();
        }

        for (OrderItemDto dto : req.getItems()) {

            OrderItem item = orderItemMapper.selectById(dto.getId());
            if (item == null) {
                throw new BusinessException("订单明细没有找到！");
            }
            ProductSkuExt sku = productSkuService.queryViewById(item.getSkuId());
            checkCanSale(sku);
            checkAddOrSubmit(obj.getTagId(), dto.getSkuId(), sku, obj.getTagRefSkuId());

            item.setSkuId(dto.getSkuId());
            item.setPrice(dto.getPrice());
            item.setQty(dto.getQty());
            item.setStartTime(dto.getStartTime());
            item.setEndTime(dto.getEndTime());
            item.setRemark(dto.getRemark());
            item.setOrderId(obj.getId());
            item.setDeliverStatus(false);
            item.setDeliverTime(null);
            item.setDeliverUserId(null);
            item.setDeliverType(dto.getDeliverType().getCode());
            item.updateById();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePlanDeliver(String orderId, List<OrderItemUpdateDto> req) {
        OrderExt order = orderExtMapper.queryById(orderId);
        if (order == null) {
            return;
        }
        if (order.getDeliverStatus()) {
            throw new BusinessException("已交付的订单不能执行此操作。");
        }

        for (OrderItemUpdateDto obj : req) {
            OrderItem orderItem = orderItemMapper.selectById(obj.getItemId());
            if (orderItem == null) {
                continue;
            }
            if (orderItem.getDeliverStatus()) {
                continue;
            }

            orderItem.setStartTime(obj.getPlanDeliverDate());
            orderItem.setRemark(obj.getRemark());
            orderItem.updateById();

            // 更新相应的工单
            for (WorkOrder wo : workOrderService.queryByItemId(obj.getItemId())) {
                // 如果工单已受理，则不更新
                if (wo.getAcceptStatus()) {
                    continue;
                }
                workOrderService.updatePlanCompleteTime(wo.getId(), obj.getPlanDeliverDate(), obj.getRemark());
            }
        }

    }

    @Override
    public void updateQtyAndPrice(OrderItemUpdateQtyAndPriceDto req) {
        OrderItem orderItem = orderItemMapper.selectById(req.getItemId());
        if (orderItem == null) {
            return;
        }

        ProductSkuExt sku = productSkuService.queryViewById(orderItem.getSkuId());
        if (sku == null) {
            throw new BusinessException("订单的商品信息没有找到。");
        }
        if (sku.getChargeType() != ProductChargeTypeEnum.AfterPay) {
            throw new BusinessException("只有后付费的商品才能执行此操作。");
        }

        OrderExt order = orderExtMapper.queryById(orderItem.getOrderId());
        if (order == null) {
            return;
        }
        if (order.getDeliverStatus()) {
            throw new BusinessException("已交付结算的订单不能执行此操作。");
        }

        orderItem.setPrice(req.getPrice());
        orderItem.setQty(req.getQty());
        orderItem.updateById();
    }

    @Override
    public void delete(String id) {
        Order order = baseMapper.selectById(id);
        if (order.getSubmitStatus()) {
            throw new BusinessException("请先撤销提交才能作废此订单。");
        }
        order.deleteById();
    }

    private boolean checkCanSale(String skuId) {
        return checkCanSale(productSkuService.queryViewById(skuId));
    }

    private boolean checkCanSale(ProductSkuExt sku) {
        if (sku == null) {
            throw new BusinessException("无效的商品。");
        }
        if (sku.getIsDelete() || sku.getSpuIsDelete()) {
            throw new BusinessException("商品 【" + sku.getNameAs() + "】 已作废，不能销售。");
        }
//        if (!sku.getIsSpuSale() || !sku.getIsSkuSale()) {
//            throw new BusinessException("商品 【" + sku.getName() + "】 已下架，不能销售。");
//        }

        if (sku.getSaleStart() != null) {
            Date d1 = sku.getSaleStart();
            Date d2 = new Date();
            if (d1.before(d2)) {
                throw new BusinessException("商品 【" + sku.getNameAs() + "】 的开售前时间为：" + DateUtils.formatDate(d1, "yyyy年MM月dd日 hh:ss") + "，请耐心等待。");
            }
        }

        if (sku.getUnitType() == ProductUnitTypeEnum.ResourceTimeLen) {
            if (sku.getResourceStatus() != ProductSkuResourceStatusEnum.Idle) {
                throw new BusinessException(sku.getNameAs() + " 状态为" + sku.getResourceStatus().toString() + " : " + sku.getResourceStatus().getDesc() + "，暂不能销售。");
            }
        }

        if (sku.getQty() <= 0 && sku.getUnitType() == ProductUnitTypeEnum.ProductQty) {
            throw new BusinessException("商品 【" + sku.getNameAs() + "】 已售完。");
        }

        return true;
    }

    private void checkSubmitAttr(String id) {
        List<OrderAttrVo> attrDefine = queryOrderAttrByOrderId(id);
        List<OrderAttr> attrRec = queryOrderAttrDetail(id);
        for (OrderAttrVo define : attrDefine) {
            if (!define.getIsSubmitRequired()) {
                continue;
            }
            Optional<OrderAttr> attr = attrRec.stream().filter(s -> define.getOrderItemId().equals(s.getOrderItemId())).filter(s -> s.getAttrId().equals(define.getId())).findFirst();
            if (!attr.isPresent()) {
                throw new BusinessException("需要上传 【" + define.getName() + "】 才能提交订单。");
            }
        }
    }

    public void checkAddOrSubmit(String defunctId, String skuId, ProductSkuExt sku, String tombSkuId) {
        String rootClassId = configureService.getValueByCode(OrderConfigureCode.tomb_spu_class_id, SecurityUtils.getTenantId());
        if (sku == null) {
            sku = productSkuService.queryViewById(skuId);
        }
        // 行业逻辑检查：殡葬
        if (SecurityUtils.getUserContent().getIndustryType() == IndustryTypeEnum.FuneralAndInterment && sku.getIsMustDefunctByOrder()) {
            Defunct defunct = defunctService.queryById(defunctId);
            if (defunct == null) {
                throw new BusinessException(String.format("购买 %s 时需要指定使用者信息。", sku.getNameAs()));
            }
            if (sku.getIsMustDefunctTombSkuByOrder() && StringUtils.isNullOrEmpty(tombSkuId)) {
                throw new BusinessException(String.format("购买 %s 时必须指定墓号位。", sku.getNameAs()));
            }

            if (!StringUtils.isNullOrEmpty(rootClassId) && !StringUtils.isNullOrEmpty(sku.getClassRootName())) {
                // 如果当前订单SKU是墓位商品，则更新
                if (rootClassId.equals(sku.getClassRootName().split(",")[0]) || !StringUtils.isNullOrEmpty(tombSkuId)) {
                    if (!StringUtils.isNullOrEmpty(defunct.getTombSkuId())) {
//                        if (!skuId.equals(defunct.getTombSkuId())) {
//                            throw new BusinessException(String.format("使用者 %s 名下已绑定了墓位，如果要重新绑定，请先将使用者与墓位解绑。", defunct.getName()));
//                        }
                        return;
                    }
                    if (StringUtils.isNullOrEmpty(tombSkuId)) {
                        defunct.setTombSkuId(sku.getId());
                    } else {
                        ProductSkuExt obj = productSkuService.queryViewById(tombSkuId);
                        if (obj == null) {
                            throw new BusinessException("指定的墓位信息无效。");
                        }
                        if (!rootClassId.equals(obj.getClassRootName().split(",")[0])) {
                            throw new BusinessException("指定的关联商品不是墓位。");
                        }
                        defunct.setTombSkuId(tombSkuId);
                    }
                    defunct.updateById();
                }
            }
        }
    }

    private int getExpireDay() {
        String expireStr = configureService.getValueByCode(OrderConfigureCode.order_money_day, SecurityUtils.getTenantId());
        int expireInt = 0;
        if (StringUtils.isNullOrEmpty(expireStr)) {
            expireInt = 0;
        } else {
            expireInt = Integer.parseInt(expireStr);
        }
        return expireInt;
    }

    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
    @CacheEvict(cacheNames = {"spu_order_rec", "spu"}, allEntries = true)
    @Override
    public void submit(String id) {

        OrderExt orderExt = orderExtMapper.queryById(id);
        if (orderExt.getTotalQty() <= 0) {
            throw new BusinessException("订单商品数量不能小于或等于0.");
        }
        if (orderExt.getSubmitStatus()) {
            throw new BusinessException("订单不能重复提交。");
        }

        // 订单状态更新
        Order order = getById(id);
        order.setSubmitStatus(true);
        order.setSubmitTime(new Date());
        order.setSubmitUserId(SecurityUtils.getUserContent().getId());
        order.setSubmitUserName(SecurityUtils.getUserContent().getPersonnelName());
        order.setPaymentExpireTime(DateUtils.plusDay(getExpireDay()));                           //设置过期时间
        order.updateById();

        // 订单属性检查
        checkSubmitAttr(id);

        // 订单库存状态检查与更新
        List<OrderItemExt> items = queryItemViewByOrderId(id);
        List<String> itemContents = new ArrayList<>();
        for (OrderItemExt item : items) {
            checkCanSale(item.getSkuId());

            // 行业逻辑检查：殡葬
            checkAddOrSubmit(order.getTagId(), item.getSkuId(), null, order.getTagRefSkuId());

            // SKU 检查
            ProductSku sku = productSkuService.queryById(item.getSkuId());
            if (sku.getQty() < item.getQty()) {
                switch (item.getUnitType()) {
                    case ResourceTimeLen:
                        //throw new BusinessException(item.getName() + " 处于 【" + item.getResourceStatus().getDesc() + "】 状态, 暂不能销售。");
                        break;
                    case Service:
                        break;
                    default:
                        throw new BusinessException(item.getName() + " 库存数量不足。");
                }
            }

            //减库存
            sku.setQty(sku.getQty() - item.getQty());
            if (item.getUnitType() == ProductUnitTypeEnum.ResourceTimeLen) {
                //资源锁定
                sku.setResourceStatus(ProductSkuResourceStatusEnum.User);
                sku.setResourceOrderItemId(item.getId());
            }
            if (item.getUnitType() == ProductUnitTypeEnum.ProductQty) {
                if (item.getDeliverType() == DeliverTypeEnum.Default) {
                    throw new BusinessException("商品 " + item.getName() + " 没有指定交付类型。");
                }
            }
            if (item.getUnitType() == ProductUnitTypeEnum.Service) {
                //当SKU的属性配置了时间周期的，则自动更新订单 Item 的交付起止时间，说明此商品按时间周期，否则按数量交付
                String expression = productSkuService.queryDeliverTimePeriodExpression(item.getSkuId());
                if (!StringUtils.isNullOrEmpty(expression)) {
                    long cnt = Long.valueOf(expression.substring(0, expression.length() - 1)) * item.getQty().longValue();
                    LocalDateTime startDate = LocalDateTime.now();
                    LocalDateTime endDate = startDate;
                    switch (expression.substring(expression.length() - 1)) {
                        case "Y":
                            endDate = endDate.plusYears(cnt);
                            break;
                        case "M":
                            endDate = endDate.plusMonths(cnt);
                            break;
                        case "d":
                            endDate = endDate.plusDays(cnt);
                            break;
                        case "h":
                            endDate = endDate.plusHours(cnt);
                            break;
                        case "m":
                            endDate = endDate.plusMinutes(cnt);
                            break;
                        default:
                            throw new BusinessException("不正确的时间周期表达式【" + expression + "】。");
                    }
                    OrderItem objItem = orderItemMapper.selectById(item.getId());
                    objItem.setStartTime(DateUtils.localDateTime2Date(startDate));
                    objItem.setEndTime(DateUtils.localDateTime2Date(endDate));
                    objItem.updateById();
                }
            }

            sku.updateById();
            itemContents.add(item.getNameAs());
        }

        // 客户订单事件发布
        CustomerTraceEvent.publishEvent(this, order.getCustId(), CustomerConfigureCode.customer_trace_dict_order, order.getCode() + "：" + String.join(",", itemContents));

        //客户订单的服务对象关联：逝者
        if (!StringUtils.isNullOrEmpty(order.getTagId())) {
            LambdaQueryWrapper<CustomerDefunct> lq = Wrappers.lambdaQuery();
            lq.eq(CustomerDefunct::getCustomerId, order.getCustId());
            lq.eq(CustomerDefunct::getDefunctId, order.getTagId());
            if (customerDefunctMapper.selectCount(lq) <= 0) {
                CustomerDefunct ref = new CustomerDefunct();
                ref.setCustomerId(order.getCustId());
                ref.setDefunctId(order.getTagId());
                ref.insert();

                CustomerTraceEvent.publishEvent(this, order.getCustId(), CustomerConfigureCode.customer_trace_dict_cust_bind_to_defunct, "客户下单后建立绑定关系。");
            }
        }
        orderExpireService.sendTask(order, 24L);
    }

    @Override
    public void submitCancel(String id, String remark) {
        submitCancel(id, remark, null, null);
    }

    @CacheEvict(cacheNames = {"spu", "spu_order_rec"}, allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void submitCancel(String id, String remark, String payDict, Double money) {
        if (StringUtils.isNullOrEmpty(remark)) {
            throw new BusinessException("撤销原因不能为空。");
        }

        Order order = baseMapper.selectNotTenantById(id);
        if (order.getAcceptStatus()) {
            int cnt = baseMapper.workOrderAcceptCount(id);
            if (cnt > 0) {
                throw new BusinessException("此订单已开始交付，不能撤销。");
            }
        }
        order.setSubmitStatus(false);
        order.setAcceptStatus(false);
        order.setDeliverStatus(false);
        order.setCancelDesc(remark);
        order.setCancelStatus(true);
        order.setCancelTime(new Date());
        order.setCancelUserId(order.getSubmitUserId());
        order.setCancelUserName(order.getSubmitUserName());
        order.updateById();

        Defunct defunct = defunctService.queryById(order.getTagId());

        //对订单明细的库存处理
        List<OrderItemExt> items = queryItemViewByOrderId(id);
        for (OrderItemExt item : items) {
            ProductSku sku = productSkuService.queryById(item.getSkuId());
            sku.setQty(sku.getQty() + item.getQty());
            if (item.getUnitType() == ProductUnitTypeEnum.ResourceTimeLen) {
                if (sku.getResourceOrderItemId().equals(item.getId())) {
                    sku.setResourceOrderItemId(null);
                    sku.setResourceStatus(ProductSkuResourceStatusEnum.Idle);
                }
            }
            sku.updateById();

            // 解除墓位绑定
            if (defunct != null) {
                if (item.getSkuId().equals(defunct.getTombSkuId())) {
                    defunct.setTombSkuId(null);
                }
            }
        }

        if (defunct != null) {
            defunct.updateById();
        }

        if (money == null) {
            money = 0d;
        } else if (money > 0) {
            throw new BusinessException("退款金额必须为负数。");
        }

        if (!(StringUtils.isNullOrEmpty(payDict) || money == null)) {
            OrderPayment backPayment = new OrderPayment();
            backPayment.setOrderId(order.getId());
            backPayment.setPayDict(payDict);
            backPayment.setMoney(money);
            backPayment.setRemark(remark);
            backPayment.insert();
        }

        CustomerTraceEvent.publishEvent(this, order.getCustId(), CustomerConfigureCode.customer_trace_dict_order_cancel, remark);
    }

    @Transactional(rollbackFor = {Exception.class, BusinessException.class})
    @Override
    public void accept(String id) {
        OrderExt orderExt = orderExtMapper.queryById(id);
        if (orderExt.getTotalQty() <= 0) {
            throw new BusinessException("订单商品数量不能小于或等于0.");
        }
        if (!orderExt.getSubmitStatus()) {
            throw new BusinessException("订单未提交。");
        }
        if (orderExt.getAcceptStatus()) {
            throw new BusinessException("订单不能重复受理。");
        }
        if (orderExt.getRealMoney() < orderExt.getRealMinMoney()) {
            throw new BusinessException("订单未支付或支付金额不足。");
        }

        Order order = getById(id);
        order.setAcceptStatus(true);
        order.setAcceptTime(new Date());
        order.setAcceptUserId(SecurityUtils.getUserContent().getId());
        order.setAcceptUserName(SecurityUtils.getUserContent().getPersonnelName());
        order.updateById();

        List<OrderItemExt> items = queryItemViewByOrderId(id);

        // 累计应付
        Double beforPayMoney;
        if (orderExt.getDiscountAuditStatus()) {
            beforPayMoney = items.stream().filter(s -> s.getChargeType() != ProductChargeTypeEnum.BeforePay)
                    .reduce(0.0, (x, y) -> x + ((y.getQty() * y.getPrice()) - y.getDiscountMoney()), Double::sum);
        } else {
            beforPayMoney = items.stream().filter(s -> s.getChargeType() != ProductChargeTypeEnum.BeforePay)
                    .reduce(0.0, (x, y) -> x + ((y.getQty() * y.getPrice())), Double::sum);
        }

        if (orderExt.getRealMoney() < beforPayMoney) {
            throw new BusinessException(String.format("受理之前，应交完全款，后付费商品除外。<br>当前应付：%6.2f<br>实际已付：%6.2f", beforPayMoney, orderExt.getRealMoney()));
        }

        int code = 0;
        for (OrderItemExt item : items) {
            //如果客户有墓位，且在受理下葬服务顺，验证是否交完全款
            if (!StringUtils.isNullOrEmpty(orderExt.getDefunctTombSkuId())) {
                String ids = configureService.getValueByCode("tomb_bury_spu_ids");
                if (!StringUtils.isNullOrEmpty(ids)) {
                    if (Arrays.stream(org.apache.commons.lang3.StringUtils.split(ids, ",")).filter(s -> s.equals(item.getSpuId())).findFirst().isPresent()) {
                        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();
                        lq.eq(OrderItemExt::getSkuId, orderExt.getDefunctTombSkuId());
                        lq.eq(OrderItemExt::getSubmitStatus, true);
                        lq.eq(OrderItemExt::getIsDelete, false);
                        lq.orderByDesc(OrderItemExt::getSubmitTime);
                        Optional<OrderItemExt> tombItem = orderItemExtMapper.selectList(lq).stream().findFirst();
                        if (tombItem.isPresent()) {
                            OrderExt ordExt = baseMapper.selectViewById(tombItem.get().getOrderId());
                            if (ordExt != null) {
                                if (ordExt.getPlanMoney().intValue() > ordExt.getRealMoney().intValue()) {
                                    throw new BusinessException(String.format("受理【%s】时，相应的墓位【%s】必须交完全款，目前还有【%s】未交。", item.getNameAs(), tombItem.get().getNameAs(), new BigDecimal(ordExt.getPlanMoney()).subtract(new BigDecimal(ordExt.getRealMoney())).setScale(2)));
                                }
                            }
                        }
                    }
                }
            }
            // 如果商品不需要自动执行交付流程，则直接交付完成
            if (!item.getIsDeliverFlow()) {
                deliverItem(item.getId());
                continue;
            }

            // 套餐商品，且有交付关系，则由父级商品交付后再生成此工单
            if (!StringUtils.isNullOrEmpty(item.getSkuItemId()) && !StringUtils.isNullOrEmpty(item.getSkuItemParentId())) {
                continue;
            }

            // 服务类商品，且是个子商品，则由父级商品交付后再生成此工单
            if (item.getUnitType() == ProductUnitTypeEnum.Service && !StringUtils.isNullOrEmpty(item.getSkuItemId())) {
                continue;
            }

            // 服务类商品，按时间段交付，而不是按数量交付，则无须预先生成工单
            if (item.getUnitType() == ProductUnitTypeEnum.Service && !StringUtils.isNullOrEmpty(productSkuService.queryDeliverTimePeriodExpression(item.getSkuId()))) {
                continue;
            }

            // 虚拟商品，不需要走交付流程，如果包含了子商品，则需要为子商品生成工单。
            if (item.getIsVirtual()) {
                //deliverItem(item.getId());
                for (WorkOrder wo : workOrderService.addReady(code++, item.getQty().intValue(), false, new WorkOrderAddDto(item.getId(), item.getRemark(), item.getStartTime()))) {
                    wo.insert();
                    workOrderService.startFollowUpItem(id, item.getId());
                }
            } else {

                // 服务类商品按订购数量生成工单数量
                if (item.getUnitType() == ProductUnitTypeEnum.Service) {
                    workOrderService.addReady(code++, item.getQty().intValue(), false, new WorkOrderAddDto(item.getId(), item.getRemark(), item.getStartTime())).stream().forEach(WorkOrder::insert);
                } else {
                    workOrderService.addReady(code++, false, new WorkOrderAddDto(item.getId(), null, item.getStartTime())).insert();
                }
            }
        }
    }

    @Override
    public void deliver(String id) {
        OrderExt orderExt = orderExtMapper.queryById(id);
        if (!orderExt.getSubmitStatus()) {
            throw new BusinessException("订单未提交。");
        }
        if (!orderExt.getAcceptStatus()) {
            throw new BusinessException("订单未受理。");
        }
        if (!orderExt.getDeliverStatus()) {
            throw new BusinessException("订单不能重复结算。");
        }
        if (orderExt.getRealMoney() < orderExt.getPlanMoney()) {
            throw new BusinessException("订单未足额支付。");
        }
        if (!orderExt.getItemDeliverStatus()) {
            throw new BusinessException("订单商品或服务没有交付完成。");
        }

        Order order = getById(id);
        order.setDeliverStatus(true);
        order.setDeliverTime(new Date());
        order.setDeliverUserId(SecurityUtils.getUserContent().getId());
        order.setDeliverUserName(SecurityUtils.getUserContent().getPersonnelName());
        order.updateById();

        CustomerTraceEvent.publishEvent(this, id, CustomerConfigureCode.customer_trace_dict_order_deliver);
    }

    @Override
    public void deliverItem(String itemId) {
        OrderItemExt item = queryItemById(itemId);
        deliverItem(item.getOrderId(), itemId, null, null);
    }

    @Override
    public void deliverItem(String itemId, Double qty, Double price) {
        OrderItemExt item = queryItemById(itemId);
        deliverItem(item.getOrderId(), itemId, qty, price);
    }

    @Transactional
    @Override
    public void deliverItem(String orderId, String ItemId, Double qty, Double price) {

        List<OrderItemExt> items = queryItemViewByOrderId(orderId);
        OrderItem item = orderItemMapper.selectById(ItemId);

//        Order order = baseMapper.selectById(item.getOrderId());
//
//        if (!order.getAcceptStatus()) {
//            throw new BusinessException("订单未受理，不能执行此操作。");
//        }

        if (item.getDeliverStatus()) {
            return;
        }

        item.setDeliverStatus(true);
        item.setDeliverTime(new Date());
        item.setDeliverUserId(SecurityUtils.getUserContent().getId());
        item.setDeliverUserName(SecurityUtils.getUserContent().getPersonnelName());
        if (qty != null) {
            item.setQty(qty);
        }
        if (price != null) {
            item.setPrice(price);
        }
        item.updateById();

        // 获取主商品SkuID
        Optional<OrderItemExt> mainItem = items.stream().filter(s -> s.getId().equals(item.getSkuId())).findFirst();
        if (mainItem.isPresent()) {
            if (!StringUtils.isNullOrEmpty(mainItem.get().getSkuItemSkuId())) {

                // 检查主商品下是否有其它未交付的子商品
                if (items.stream()
                        .filter(s -> s.getSkuItemSkuId().equals(mainItem.get().getSkuItemSkuId()))    // 所有主商品为currSkuItemSkuId
                        .filter(s -> s.getDeliverStatus() == false)                                   // 未交付的
                        .filter(s -> !s.getId().equals(item.getId()))                                 // 排除当前要交付的
                        .count() == 0) {

                    //可以交付主商品
                    OrderItem updateItem = new OrderItem();
                    updateItem.setId(mainItem.get().getId());
                    updateItem.setDeliverStatus(true);
                    updateItem.setDeliverTime(new Date());
                    updateItem.setDeliverUserId(SecurityUtils.getUserContent().getId());
                    updateItem.setDeliverUserName(SecurityUtils.getUserContent().getPersonnelName());
                    updateItem.updateById();
                }
            }
        }


    }

    @Override
    public OrderWxPayResponse preWxPay(String id, String openId) throws NoSuchAlgorithmException, UnsupportedEncodingException {

        if (StringUtils.isNullOrEmpty(openId)) {
            if (SecurityUtils.getUserContent() == null) {
                throw new BusinessPermissionDeniedException("userContext 为空。");
            }
            openId = userService.getOpenId(SecurityUtils.getUserContent().getId(), SecurityUtils.getTenantId());
        }
        if (StringUtils.isNullOrEmpty(openId)) {
            logger.error("当前OpenID " + openId + " 不能为空。");
            throw new BusinessException("当前OpenID " + openId + " 不能为空。");
        }

        OrderVo order = queryById(id);
        String body = order.getItems().stream().map(s -> s.getClassName()).distinct().collect(Collectors.joining(","));
        String deviceInfo = "web-ebs";

        WxPayService wxPayService = wxService.getWxPayService(order.getTenantId());
        if (StringUtils.isNullOrEmpty(wxPayService.getConfig().getAppId()) || StringUtils.isNullOrEmpty(wxPayService.getConfig().getMchId()) || StringUtils.isNullOrEmpty(wxPayService.getConfig().getMchKey())) {
            logger.error("租户[" + order.getTenantId() + "]下没有配置微信商户号。");
            throw new BusinessException("当前租户下没有配置微信商户号，不能进行微信支付。");
        }
        if (!order.getSubmitStatus()) {
            throw new BusinessException("订单没有提交，不能执行此操作。");
        }
        if (order.getRealMoney() >= order.getPlanMoney()) {
            throw new BusinessException("订单已付款。");
        }

        String nonceStr = StringUtils.randStr(32);
        String signKey = String.format("appId=%s&body=%s&device_info=%s&mch_id=%s&nonce_str=%s&key=%s", wxPayService.getConfig().getAppId(), body, deviceInfo, wxPayService.getConfig().getMchId(), nonceStr, wxPayService.getConfig().getMchKey());

        MessageDigest msgDigest = MessageDigest.getInstance("MD5");
        msgDigest.update(signKey.getBytes(StandardCharsets.UTF_8), 0, signKey.length());
        String sign = DatatypeConverter.printHexBinary(msgDigest.digest()).toUpperCase();

        // 生成预支付订单号
        String prepayKey = "wx-pay-" + id;
        String prepayId = null;
        try {
            WxPayOrderQueryResult resultQuery = wxPayService.queryOrder(null, order.getCode());

            // 如果执行失败，以下代码都不会执行，queryOrder会直接抛出 WxPayException
            // 预支付订单存在
            if ("SUCCESS".equals(resultQuery.getReturnCode())) {
                if ("SUCCESS".equals(resultQuery.getResultCode())) {
                    if ("NOTPAY".equals(resultQuery.getTradeState())) {
                        //未付成功
                        Object obj = redisService.get(prepayKey);
                        if (obj == null) {
                            logger.error("系统错误，当前预支付订单号没有找到。");
                            throw new BusinessException("系统错误，当前预支付订单号没有找到。");
                        }
                        prepayId = obj.toString();
                    } else {
                        logger.error("当前订单状态为：" + resultQuery.getTradeState());
                        throw new BusinessException("当前订单状态为：" + resultQuery.getTradeState());
                    }
                } else {
                    logger.error("预支付订单异常：" + resultQuery.getErrCode() + " - " + resultQuery.getErrCodeDes());
                    throw new BusinessException("预支付订单异常：" + resultQuery.getErrCode() + " - " + resultQuery.getErrCodeDes());
                }
                // 预支付订单不存在
            }
        } catch (WxPayException e) {
            if ("ORDERNOTEXIST".equals(e.getErrCode())) {
                logger.error("没有找到预支付订单，系统将创建新的预支付ID");
            }

            Double totalFee = order.getPlanMoney().doubleValue() * 100.0d;

            // 统一下单
            WxPayUnifiedOrderRequest wxpay = new WxPayUnifiedOrderRequest();
            wxpay.setSign(sign);
            wxpay.setNonceStr(nonceStr);
            wxpay.setBody(body);
            wxpay.setDetail(order.getItems().stream().map(s -> s.getName()).distinct().collect(Collectors.joining(",")));
            wxpay.setTotalFee(totalFee.intValue());
            wxpay.setOutTradeNo(order.getCode());
            wxpay.setNotifyUrl("http://dev.cloud-client.cn:8080/order/wxPayNotify/" + openId + "/" + order.getId());
            wxpay.setOpenid(openId);
            wxpay.setDeviceInfo(deviceInfo);
            wxpay.setSignType("MD5");
            wxpay.setFeeType("CNY");
            wxpay.setSpbillCreateIp("127.0.0.1");
            wxpay.setTradeType("JSAPI");
            WxPayUnifiedOrderResult response = null;
            try {
                response = wxPayService.unifiedOrder(wxpay);
            } catch (WxPayException ex) {
                logger.error("生成预支付单失败：" + ex.getErrCode() + " - " + ex.getErrCodeDes());
                ex.printStackTrace();
                throw new BusinessException("生成预支付单失败：" + e.getErrCode() + " - " + ex.getErrCodeDes());
            }
            prepayId = response.getPrepayId();

            // 缓存:1个小时
            redisService.set(prepayKey, prepayId, 60L * 120L);
        }

        // 生成签名
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000 >> 0);
        String packageValue = "prepay_id=" + prepayId;
        String paySignKey = String.format("appId=%s&nonceStr=%s&package=%s&signType=%s&timeStamp=%s&key=%s",
                wxPayService.getConfig().getAppId(),
                nonceStr,
                packageValue,
                "MD5",
                timeStamp,
                wxPayService.getConfig().getMchKey());
        msgDigest.update(paySignKey.getBytes(StandardCharsets.UTF_8), 0, paySignKey.length());
        String paySign = DatatypeConverter.printHexBinary(msgDigest.digest()).toUpperCase();

        return new OrderWxPayResponse(wxPayService.getConfig().getAppId(), timeStamp, nonceStr, packageValue, "MD5", paySign);
    }

    @CacheEvict(cacheNames = "spu_order_rec", allEntries = true)
    @Override
    public void payment(OrderPayDto req, String userId) {
        OrderExt orderExt = orderExtMapper.queryById(req.getOrderId());
        if (!orderExt.getSubmitStatus()) {
            throw new BusinessException("订单未提交。");
        }

        OrderPayment orderPayment = new OrderPayment();
        orderPayment.setOrderId(req.getOrderId());
        orderPayment.setPayDict(req.getPayDict());
        orderPayment.setAccountNo(req.getAccountNo());
        orderPayment.setMoney(req.getMoney());
        orderPayment.setRemark(req.getRemark());
        orderPayment.setCreateAt(userId);
        orderPayment.setCreateTime(new Date());
        orderPayment.setTenantId(orderExt.getTenantId());
        orderPayment.insert();
    }

    @Override
    public void paymentBack(OrderPayDto req) {
        OrderExt orderExt = orderExtMapper.queryById(req.getOrderId());
        if (!orderExt.getSubmitStatus()) {
            throw new BusinessException("订单未提交。");
        }
        if (orderExt.getRealMoney() < req.getMoney()) {
            throw new BusinessException("退款金额不能大于已收款金额。");
        }
        OrderPayment orderPayment = new OrderPayment();
        orderPayment.setOrderId(req.getOrderId());
        orderPayment.setPayDict(req.getPayDict());
        orderPayment.setAccountNo(req.getAccountNo());
        orderPayment.setMoney(getAbsNegative(req.getMoney()));
        orderPayment.setRemark(req.getRemark());
        orderPayment.insert();
    }

    @Override
    public OrderVo queryById(String id) {
        OrderExt orderExt = orderExtMapper.queryById(id);
        if (orderExt == null) {
            throw new BusinessEntityNotFoundException(id, "订单");
        }
        return queryById(orderExt);
    }

    private OrderVo queryById(OrderExt order) {
        if (order == null) {
            return null;
        }
        OrderVo result = new OrderVo();
        BeanUtils.copyProperties(order, result);

        List<OrderItemExt> items = orderItemExtMapper.queryItemByOrderId(order.getId());
        List<OrderItemAttrVo> itemAttrs = new ArrayList<>();
        for (int i = 0; i < items.size(); i++) {
            OrderItemAttrVo obj = new OrderItemAttrVo();
            BeanUtils.copyProperties(items.get(i), obj);
            LambdaQueryWrapper<OrderAttr> lqAttr = Wrappers.lambdaQuery();
            lqAttr.eq(OrderAttr::getOrderItemId, items.get(i).getId());
            obj.setAttrs(orderAttrMapper.selectList(lqAttr));
            for (OrderAttr attr : obj.getAttrs()) {
                attr.setFileUrl(OSSUtil.getObjectUrl(attr.getFileUrl()).toString());
            }

            itemAttrs.add(obj);
        }
        result.setItems(itemAttrs);
        return result;
    }

    @Override
    public IPage<OrderItemExt> queryItem(String searchText, OrderStatusEnum status, Integer pageSize, Integer pageIndex) {
        Page<OrderItemExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();

        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.like(OrderItemExt::getOrderCode, searchText);
            lq.like(OrderItemExt::getSkuCode, searchText);
            lq.like(OrderItemExt::getName, searchText);
            lq.like(OrderItemExt::getCustName, searchText);
            lq.like(OrderItemExt::getLinkmanPhone, searchText);
        }
        if (status != null) {
            switch (status) {
                case Create:
                    lq.eq(OrderItemExt::getSubmitStatus, false);
                    lq.eq(OrderItemExt::getAcceptStatus, false);
                    lq.eq(OrderItemExt::getDeliverStatus, false);
                    break;
                case Submit:
                    lq.eq(OrderItemExt::getSubmitStatus, true);
                    lq.eq(OrderItemExt::getDeliverStatus, false);
                    break;
                case Accept:
                    lq.eq(OrderItemExt::getSubmitStatus, true);
                    lq.eq(OrderItemExt::getAcceptStatus, false);
                    lq.eq(OrderItemExt::getDeliverStatus, false);
                    break;
                case Deliver:
                    lq.eq(OrderItemExt::getSubmitStatus, true);
                    lq.eq(OrderItemExt::getAcceptStatus, true);
                    lq.eq(OrderItemExt::getDeliverStatus, true);
                    break;
            }
        }
        return orderItemExtMapper.selectPage(page, lq);

    }

    @Override
    public List<OrderItemExt> queryItemViewByOrderId(String id) {
        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderItemExt::getOrderId, id);
        lq.orderByAsc(OrderItemExt::getDeliverSort);
        return orderItemExtMapper.selectList(lq);
    }

    @Override
    public List<GroupListInfo<OrderVo>> queryStatusCountByUserId(String id) {
        List<CustomerAndDefunctExt> customerAndDefunctExts = customerService.queryCurrentCustomerAndDefunct();

        LambdaQueryWrapper<OrderExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderExt::getCreateAt, id).or().eq(OrderExt::getCustUserId, id);

        List<String> customerIds = customerAndDefunctExts.stream().map(s -> s.getCustomerId()).distinct().collect(Collectors.toList());
        List<String> defunctIds = customerAndDefunctExts.stream().map(s -> s.getDefunctId()).distinct().collect(Collectors.toList());
        if (!StringUtils.isNullOrEmpty(customerIds)) {
            lq.in(OrderExt::getCustId, customerIds).or().in(OrderExt::getTagId, defunctIds);
        }
        lq.orderByDesc(OrderExt::getCode);
        List<OrderExt> list = orderExtMapper.selectList(lq);
        List<OrderVo> vos = new ArrayList<>();
        for (OrderExt order : list) {
            vos.add(queryById(order));
        }

        List<GroupListInfo<OrderVo>> result = new ArrayList<>();
        GroupListInfo<OrderVo> g1 = new GroupListInfo();
        g1.setCount((int) list.stream().count());
        g1.setName("全部");
        g1.setId("1");
        g1.setItems(vos);
        result.add(g1);

        GroupListInfo<OrderVo> g2 = new GroupListInfo();
        g2.setCount((int) list.stream().filter(s -> s.getOrderStatus() == OrderStatusEnum.Default || s.getOrderStatus() == OrderStatusEnum.Create || s.getOrderStatus() == OrderStatusEnum.Submit).count());
        g2.setName("待付款");
        g2.setId("2");
        g2.setItems(vos.stream().filter(s -> s.getOrderStatus() == OrderStatusEnum.Default || s.getOrderStatus() == OrderStatusEnum.Create || s.getOrderStatus() == OrderStatusEnum.Submit).collect(Collectors.toList()));
        result.add(g2);

        GroupListInfo<OrderVo> g3 = new GroupListInfo();
        g3.setCount((int) list.stream().filter(s -> s.getOrderStatus() == OrderStatusEnum.Accept).count());
        g3.setName("进行中");
        g3.setId("3");
        g3.setItems(vos.stream().filter(s -> s.getOrderStatus() == OrderStatusEnum.Accept).collect(Collectors.toList()));
        result.add(g3);

        GroupListInfo<OrderVo> g4 = new GroupListInfo();
        g4.setCount((int) list.stream().filter(s -> s.getOrderStatus() == OrderStatusEnum.Deliver).count());
        g4.setName("已完成");
        g4.setId("4");
        g4.setItems(vos.stream().filter(s -> s.getOrderStatus() == OrderStatusEnum.Deliver).collect(Collectors.toList()));
        result.add(g4);

        GroupListInfo<OrderVo> g5 = new GroupListInfo();
        g5.setCount((int) list.stream().filter(s -> s.getOrderStatus() == OrderStatusEnum.Cancel).count());
        g5.setName("已取消");
        g5.setId("5");
        g4.setItems(vos.stream().filter(s -> s.getOrderStatus() == OrderStatusEnum.Cancel).collect(Collectors.toList()));
        result.add(g5);
        return result;
    }

    @Override
    public List<OrderExt> queryByCustId(String id) {
        List<String> ids = new ArrayList<>();
        ids.add(id);
        return queryByCustId(ids);
    }

    @Override
    public List<OrderExt> queryByCustId(List<String> ids) {
        if (ids.size() <= 0) {
            return null;
        }
        LambdaQueryWrapper<OrderExt> lq = Wrappers.lambdaQuery();
        lq.in(OrderExt::getCustId, ids);
        lq.orderByDesc(OrderExt::getCreateTime);
        return orderExtMapper.selectList(lq);
    }

    @Override
    public OrderItemExt queryItemById(String itemId) {
        return orderItemExtMapper.selectById(itemId);
    }

    @Override
    public List<OrderItemBookByDto> queryBookRec(String custId) {
        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderItemExt::getSubmitStatus, true);
        lq.eq(OrderItemExt::getAcceptStatus, true);
        lq.eq(OrderItemExt::getDeliverStatus, false);
        lq.isNull(OrderItemExt::getDeliverTime);
        if (StringUtils.isNullOrEmpty(custId)) {
            List<String> ids = customerService.queryCustIdByUserId(UserContext.getInstance().getId());
            if (StringUtils.isNullOrEmpty(ids)) {
                return null;
            } else {
                lq.in(OrderItemExt::getCustId, ids);
            }
        } else {
            lq.eq(OrderItemExt::getCustId, custId);
        }
        return orderItemExtMapper.selectList(lq).stream().map(s -> {
            OrderItemBookByDto obj = new OrderItemBookByDto();
            obj.setItemId(s.getId());
            obj.setName(s.getNameAs());
            obj.setOrderTime(s.getSubmitTime());
            obj.setServicePersonName(s.getPersonnelName());
            return obj;
        }).collect(Collectors.toList());
    }

    @Override
    public List<OrderItemPlanDeliverDto> queryPlanDeliverItem(String searchText) {
        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderItemExt::getAcceptStatus, true);
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.like(OrderItemExt::getCustName, searchText).or()
                    .like(OrderItemExt::getDefunctName, searchText).or()
                    .like(OrderItemExt::getLinkmanPhone, searchText).or()
                    .like(OrderItemExt::getOrderCode, searchText).or()
                    .like(OrderItemExt::getNameAs, searchText);
        }
        lq.eq(OrderItemExt::getDeliverStatus, false);
        lq.eq(OrderItemExt::getWorkOrderAcceptStatus, false);
        lq.eq(OrderItemExt::getTenantId, SecurityUtils.getUserContent().getTenantId());
        lq.orderByDesc(OrderItemExt::getAcceptTime);
        return orderItemExtMapper.selectList(lq).stream().filter(s -> s.getIsVirtual() == false).map(s -> {
            OrderItemPlanDeliverDto obj = new OrderItemPlanDeliverDto();
            obj.setId(s.getId());
            obj.setSkuId(s.getSkuId());
            obj.setParentSkuId(s.getSkuItemSkuId());
            obj.setSkuName(s.getNameAs());
            obj.setQty(s.getQty());
            obj.setIsVirtual(s.getIsVirtual());
            obj.setAcceptStatus(s.getAcceptStatus());
            obj.setAcceptTime(s.getAcceptTime());
            obj.setAcceptUserName(s.getAcceptUserName());
            obj.setPersonnelName(s.getPersonnelName());
            obj.setOrderCode(s.getOrderCode());
            obj.setCustName(s.getCustName());
            obj.setPhone(s.getLinkmanPhone());
            obj.setDefunctName(s.getDefunctName());
            obj.setTombSkuNameAs(s.getTombSkuNameAs());
            obj.setSaleDesc(s.getSaleAttrDesc());
            obj.setPaymentStatus(s.getPaymentStatus());
            obj.setWorkOrderCount(s.getWorkOrderCount());
            obj.setStartTime(s.getStartTime());
            obj.setWorkOrders(workOrderService.queryViewByItemId(s.getId()).stream().filter(p -> p.getAcceptStatus() == false).collect(Collectors.toList()));
            return obj;
        }).filter(s -> s.getWorkOrderCount() > 0).collect(Collectors.toList());
    }

    @Override
    public List<OrderExt> queryByTrace(String id) {
        LambdaQueryWrapper<OrderExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderExt::getTraceId, id);
        lq.eq(OrderExt::getIsDelete, false);
        return orderExtMapper.selectList(lq);
    }

    @Override
    public List<OrderItemPlanDeliverDto> queryPlanDeliverItemByTimePeriod(String searchText) {
        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderItemExt::getAcceptStatus, true);
        lq.isNotNull(OrderItemExt::getEndTime);
        lq.eq(OrderItemExt::getDeliverStatus, false);
        lq.eq(OrderItemExt::getTenantId, SecurityUtils.getUserContent().getTenantId());
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.and(wq -> wq.like(OrderItemExt::getCustName, searchText).or()
                    .like(OrderItemExt::getDefunctName, searchText).or()
                    .like(OrderItemExt::getLinkmanPhone, searchText).or()
                    .like(OrderItemExt::getOrderCode, searchText).or()
                    .like(OrderItemExt::getNameAs, searchText).or()
                    .like(OrderItemExt::getTombSkuNameAs, searchText));
        }
        lq.orderByAsc(OrderItemExt::getEndTime);
        return orderItemExtMapper.selectList(lq).stream().filter(s -> s.getIsVirtual() == false).map(s -> {
            OrderItemPlanDeliverDto obj = new OrderItemPlanDeliverDto();
            obj.setId(s.getId());
            obj.setSkuId(s.getSkuId());
            obj.setParentSkuId(s.getSkuItemSkuId());
            obj.setSkuName(s.getNameAs());
            obj.setQty(s.getQty());
            obj.setIsVirtual(s.getIsVirtual());
            obj.setAcceptStatus(s.getAcceptStatus());
            obj.setAcceptTime(s.getAcceptTime());
            obj.setAcceptUserName(s.getAcceptUserName());
            obj.setPersonnelName(s.getPersonnelName());
            obj.setOrderCode(s.getOrderCode());
            obj.setCustName(s.getCustName());
            obj.setPhone(s.getLinkmanPhone());
            obj.setDefunctName(s.getDefunctName());
            obj.setTombSkuNameAs(s.getTombSkuNameAs());
            obj.setSaleDesc(s.getSaleAttrDesc());
            obj.setStartTime(s.getStartTime());
            obj.setEndTime(s.getEndTime());
            obj.setPaymentStatus(s.getPaymentStatus());
            obj.setWorkOrderCount(s.getWorkOrderCount());
            obj.setWorkOrders(workOrderService.queryViewByItemId(s.getId()).stream().collect(Collectors.toList()));
            return obj;
        }).collect(Collectors.toList());
    }

    @Override
    public OrderBzVo queryBzOrderByCustId(String id) {
        LambdaQueryWrapper<BzOrder> lq = Wrappers.lambdaQuery();
        lq.eq(BzOrder::getCustId, id);
        List<BzOrder> list = bzOrderMapper.selectList(lq);
        Optional<OrderBzVo> result = list.stream().map(s -> {
            OrderBzVo obj = new OrderBzVo();
            obj.setCustName(s.getCustName());
            obj.setCustPhone(s.getCustPhone());
            obj.setDefunctName(s.getDefunctName());
            return obj;
        }).distinct().findFirst();

        if (!result.isPresent()) {
            return null;
        }

        result.get().setTotalMoney(list.stream().collect(Collectors.summingDouble(BzOrder::getTotalMoney)));
        result.get().setFirstDiscount(list.stream().collect(Collectors.summingDouble(BzOrder::getFirstDiscount)));
        result.get().setSecondDiscount(list.stream().collect(Collectors.summingDouble(BzOrder::getSecondDiscount)));
        result.get().setOtherDiscount(list.stream().collect(Collectors.summingDouble(BzOrder::getOtherDiscount)));

        List<OrderBzItemVo> items = new ArrayList<>();
        for (BzOrder item : list) {
            OrderBzItemVo objItem = new OrderBzItemVo();
            objItem.setSkuId(item.getSkuId());
            objItem.setSkuName(item.getSkuName());
            objItem.setMoney(item.getTotalMoney());
            objItem.setFirstDiscount(item.getFirstDiscount());
            objItem.setSecondDiscount(item.getSecondDiscount());
            objItem.setOtherDiscount(item.getOtherDiscount());
            objItem.setTotalDiscount(item.getFirstDiscount() + item.getSecondDiscount() + item.getOtherDiscount());
            items.add(objItem);
        }
        result.get().setItems(items);
        return result.get();
    }

    @Override
    public void recordNotifyByCustId(String id) {
        BzOrderNotify obj = new BzOrderNotify();
        obj.setCustId(id);
        obj.insert();
    }

    /**
     * 计算退款金额
     *
     * @param value
     * @return
     */
    private Double getAbsNegative(Double value) {
        return Math.abs(value) - (Math.abs(value) * 2);
    }

    @Override
    public List<OrderAttrVo> queryOrderAttrByOrderId(String id) {
        List<OrderAttrVo> result = new ArrayList<>();
        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderItemExt::getOrderId, id);
        List<OrderItemExt> items = orderItemExtMapper.selectList(lq);

        if (items.size() <= 0) {
            return result;
        }
        List<String> classIds = orderItemExtMapper.selectList(lq).stream().map(s -> s.getClassId()).distinct().collect(Collectors.toList());

        List<String> parents = new ArrayList<>();
        for (String currId : classIds) {
            List<String> ids = productClassService.queryParentIds(currId);
            if (ids != null) {
                parents.addAll(ids);
            }
        }
        LambdaQueryWrapper<ProductClassOrderAttrExt> lqAttr = Wrappers.lambdaQuery();
        lqAttr.in(ProductClassOrderAttrExt::getClassId, parents);
        lqAttr.eq(ProductClassOrderAttrExt::getIsDelete, false);

        List<String> ids = parents.stream().distinct().collect(Collectors.toList());
        for (OrderItemExt item : items) {
            List<ProductClassOrderAttrExt> classAttrs = queryOrderAttrBySkuId(item.getSkuId());
            for (ProductClassOrderAttrExt attr : classAttrs) {
                OrderAttrVo obj = new OrderAttrVo();
                BeanUtils.copyProperties(attr, obj);
                obj.setOrderItemId(item.getId());
                result.add(obj);
            }
        }
        return result;
    }

    public List<OrderAttr> queryOrderAttrDetail(String orderId) {
        LambdaQueryWrapper<OrderItem> lq = Wrappers.lambdaQuery();
        lq.eq(OrderItem::getOrderId, orderId);
        List<String> itemIds = orderItemMapper.selectList(lq).stream().map(s -> s.getId()).collect(Collectors.toList());

        if (itemIds == null) {
            return new ArrayList<>();
        }
        if (itemIds.size() <= 0) {
            return new ArrayList<>();
        }

        LambdaQueryWrapper<OrderAttr> lqAttr = Wrappers.lambdaQuery();
        lqAttr.in(OrderAttr::getOrderItemId, itemIds);
        return orderAttrMapper.selectList(lqAttr);
    }

    @Cacheable(cacheNames = "product_class_attr", key = "order_attr-#classId")
    public List<ProductClassOrderAttrExt> queryOrderAttr(String classId) {
        List<String> classIds = productClassService.queryParentIds(classId);
        LambdaQueryWrapper<ProductClassOrderAttrExt> lq = Wrappers.lambdaQuery();
        lq.in(ProductClassOrderAttrExt::getClassId, classIds);
        lq.eq(ProductClassOrderAttrExt::getIsDelete, false);
        lq.orderByAsc(ProductClassOrderAttrExt::getGroupSort);
        lq.orderByAsc(ProductClassOrderAttrExt::getSort);
        return productClassOrderAttrExtMapper.selectList(lq);
    }

    @Override
    public IPage<OrderExt> query(String createUserId, String searchText, OrderStatusEnum status, int pageSize, int pageIndex) {
        Page<OrderExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<OrderExt> lq = Wrappers.lambdaQuery();
        if (status == null) {
            status = OrderStatusEnum.Create;
        }
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.and(s -> s.like(OrderExt::getCustName, searchText).or()
                    .like(OrderExt::getCode, searchText).or()
                    .like(OrderExt::getLinkman, searchText).or()
                    .like(OrderExt::getLinkmanPhone, searchText));
        }
        if (!StringUtils.isNullOrEmpty(createUserId)) {
            lq.eq(OrderExt::getCreateAt, SecurityUtils.getUserContent().getId());
        }
        lq.eq(OrderExt::getIsDelete, false);
        switch (status) {
            case Create:
                lq.eq(OrderExt::getSubmitStatus, false);
                lq.eq(OrderExt::getAcceptStatus, false);
                lq.eq(OrderExt::getDeliverStatus, false);
                lq.orderByDesc(OrderExt::getCreateTime);
                break;
            case Submit:
                lq.eq(OrderExt::getSubmitStatus, true);
                lq.eq(OrderExt::getDeliverStatus, false);
                lq.apply("plan_money > real_money");
                lq.orderByDesc(OrderExt::getSubmitTime);
                break;
            case Accept:
                lq.eq(OrderExt::getSubmitStatus, true);
                lq.eq(OrderExt::getAcceptStatus, false);
                lq.eq(OrderExt::getDeliverStatus, false);
                lq.apply("real_money >= real_min_money");
                lq.orderByDesc(OrderExt::getAcceptTime);
                break;
            case Deliver:
                lq.eq(OrderExt::getSubmitStatus, true);
                lq.eq(OrderExt::getAcceptStatus, true);
                lq.eq(OrderExt::getDeliverStatus, true);
                lq.eq(OrderExt::getItemDeliverStatus, true);
                lq.orderByDesc(OrderExt::getDeliverTime);
                break;
            default:
                lq.orderByDesc(OrderExt::getSubmitTime);
                break;
        }
        return orderExtMapper.selectPage(page, lq);
    }

    @Override
    public List<ProductClassOrderAttrExt> queryOrderAttrBySkuId(String id) {
        ProductSkuExt obj = productSkuService.queryViewById(id);
        if (obj != null) {
            return queryOrderAttr(obj.getClassId());
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public boolean saveBatch(Collection<Order> entityList) {
        return false;
    }

    @Override
    public List<ProductClassOrderAttrExt> queryOrderAttrBySpuId(String id) {
        ProductExt obj = productService.queryById(id);
        if (obj != null) {
            return queryOrderAttr(obj.getClassId());
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public List<ProductClassOrderAttrVO> convertOrderAttrToGroupList(List<ProductClassOrderAttrExt> list) {
        List<ProductClassOrderAttrVO> result = list.stream().map(s -> {
            ProductClassOrderAttrVO obj = new ProductClassOrderAttrVO();
            obj.setGroupId(s.getGroupId());
            obj.setGroupName(s.getGroupName());
            obj.setGroupSort(s.getGroupSort());
            return obj;
        }).distinct().collect(Collectors.toList());
        for (int i = 0; i < result.size(); i++) {
            String groupId = result.get(i).getGroupId();
            result.get(i).setAttrs(list.stream().filter(s -> groupId.equals(s.getGroupId())).collect(Collectors.toList()));
        }
        return result;
    }

    @Override
    public List<ProductClassOrderAttrVO> convertOrderAttrVoToGroupList(List<OrderAttrVo> list) {
        List<ProductClassOrderAttrVO> result = list.stream().map(s -> {
            ProductClassOrderAttrVO obj = new ProductClassOrderAttrVO();
            obj.setGroupId(s.getGroupId());
            obj.setGroupName(s.getGroupName());
            obj.setGroupSort(s.getGroupSort());
            return obj;
        }).distinct().collect(Collectors.toList());
        for (int i = 0; i < result.size(); i++) {
            String groupId = result.get(i).getGroupId();
            result.get(i).setAttrs(list.stream().filter(s -> groupId.equals(s.getGroupId())).collect(Collectors.toList()));
        }
        return result;
    }

    @Override
    public List<String> addFile(String itemId, String attrId, List<MultipartFile> files) {
        if (files == null) {
            return null;
        }
        if (files.size() <= 0) {
            return null;
        }

        ProductClassOrderAttrExt attr = productClassOrderAttrExtMapper.selectById(attrId);
        if (attr == null) {
            throw new BusinessEntityNotFoundException(attrId, "商品的订单属性");
        }

        OrderItemExt item = queryItemById(itemId);
        List<ProductClassOrderAttrExt> attrs = queryOrderAttr(item.getClassId());

        if (attrs.size() <= 0) {
            throw new BusinessException("指定的订单项不需要上传文件。");
        }

        List<String> ids = new ArrayList<>();
        List<String> keys = OSSUtil.batchUpload(files, String.format("%s/%s/%s/", prefix, itemId, attrId));

        for (MultipartFile file : files) {
            if (keys.size() > 0) {
                OrderAttr obj = new OrderAttr();
                obj.setAttrId(attrId);
                obj.setAttrName(attr.getName());
                obj.setOrderId(item.getOrderId());
                obj.setOrderItemId(item.getId());
                obj.setFileUrl(String.join(",", keys));
                obj.setFileName(String.join(",", keys));
                obj.setIsSubmit(false);
                obj.insert();
                //urls.add(OSSUtil.getObjectUrl(String.join(",", keys)).toString());
                ids.add(obj.getId());
            }
        }
        return ids;
    }

    @Override
    public void removeFile(String id) {
        OrderAttr attr = orderAttrMapper.selectById(id);
        if (attr != null) {
            OSSUtil.delete(attr.getFileUrl());
            attr.deleteById();
        }
    }

    @Override
    public void submitFile(String itemId) {
        OrderItemExt item = queryItemById(itemId);
        if (item.getDeliverStatus()) {
            throw new BusinessException("订单项目已交付，不能重新提交项目资料。");
        }

        LambdaQueryWrapper<OrderAttr> lq = Wrappers.lambdaQuery();
        lq.eq(OrderAttr::getOrderItemId, itemId);
        lq.eq(OrderAttr::getIsSubmit, false);
        List<OrderAttr> list = orderAttrMapper.selectList(lq);
        for (OrderAttr obj : list) {
            obj.setIsSubmit(true);
            obj.updateById();
        }
    }

    @Override
    public void cancelSubmitFile(String itemId, String desc) {
        OrderItemExt item = queryItemById(itemId);
        if (item.getDeliverStatus()) {
            throw new BusinessException("订单项目已交付，不能撤销提交。");
        }

        LambdaQueryWrapper<OrderAttr> lq = Wrappers.lambdaQuery();
        lq.eq(OrderAttr::getOrderItemId, itemId);
        lq.eq(OrderAttr::getIsSubmit, true);
        List<OrderAttr> list = orderAttrMapper.selectList(lq);
        for (OrderAttr obj : list) {
            obj.setIsSubmit(false);
            obj.setCancelSubmitRemark(desc);
            obj.updateById();
        }
    }

    @Override
    public void timeOutCancel(String id) {

    }

    @Override
    public void expireApply(OrderExpireApplyDto req) {
        OrderExt obj = queryById(req.getOrderId());
        if (obj == null) {
            throw new BusinessEntityNotFoundException(req.getOrderId(), "订单");
        }

        if (!obj.getSubmitStatus()) {
            throw new BusinessException("订单没有提交，不能执行此操作。");
        }
        if (obj.getPaymentStatus() == PaymentStatusEnum.Complete) {
            throw new BusinessException("订单已完成支付，不能执行此操作。");
        }

        Order order = new Order();
        order.setId(obj.getId());
        order.setPaymentExpireApplyTime(req.getExpireDate());
        order.setPaymentExpireApplyAuditUserId(req.getAuditUserId());
        order.updateById();
    }

    @Override
    public void expireApplyAudit(OrderExpireApplyAuditDto req) {
        OrderExt obj = queryById(req.getOrderId());
        if (obj == null) {
            throw new BusinessEntityNotFoundException(req.getOrderId(), "订单");
        }
        if (!obj.getSubmitStatus()) {
            throw new BusinessException("订单没有提交，不能执行此操作。");
        }
        if (obj.getPaymentStatus() == PaymentStatusEnum.Complete) {
            throw new BusinessException("订单已完成支付，不能执行此操作。");
        }
        if (obj.getPaymentExpireTime() == null) {
            throw new BusinessException("延期申请没有指定延期时间。");
        }
        if (obj.getPaymentExpireApplyStatus()) {
            throw new BusinessException("订单的延期申请已审批过。");
        }

        Order order = new Order();
        order.setId(obj.getId());
        if (req.getPass()) {
            order.setPaymentExpireTime(req.getExpireDate());
            order.setPaymentExpireApplyTime(req.getExpireDate());
        }
        order.setPaymentExpireApplyAuditUserId(SecurityUtils.getUserContent().getId());
        order.setPaymentExpireApplyAuditUserName(SecurityUtils.getUserContent().getPersonnelName());
        order.setPaymentExpireApplyStatus(req.getPass());
        order.setPaymentExpireApplyAuditTime(new Date());
        order.updateById();
    }

    @Transactional
    @Override
    public void discountApply(OrderDiscountApplyDto req) {
        OrderExt order = queryById(req.getOrderId());
        if (order == null) {
            throw new BusinessEntityNotFoundException(req.getOrderId(), "订单");
        }
        if (order.getPaymentStatus() == PaymentStatusEnum.Complete) {
            throw new BusinessException("此订单已付完全款，不能再申请优惠。");
        }
        if (order.getAcceptStatus()) {
            throw new BusinessException("此订单已受理，不能再申请优惠 。");
        }
        if (req.getItems().stream().collect(Collectors.summingDouble(s -> s.getDiscountMoney())) > order.getPlanMoney()) {
            throw new BusinessException("优惠金额不能高于订单应付金额。");
        }
        if (req.getItems().stream().collect(Collectors.summingDouble(s -> s.getDiscountMoney())) <= 0) {
            throw new BusinessException("优惠金额不能小于或等于零。");
        }

        for (OrderDiscountApplyItemDto item : req.getItems()) {
            OrderItem obj = orderItemMapper.selectById(item.getItemId());
            if (obj == null) {
                throw new BusinessEntityNotFoundException(item.getItemId(), "订单明细");
            }
            obj.setDiscountMoney(item.getDiscountMoney());
            obj.updateById();
        }

        Personnel personnel = personnelService.queryByUserId(req.getAuditUserId());
        if (personnel == null) {
            throw new BusinessException("无效的审核人。");
        }

        Order updateOrder = new Order();
        updateOrder.setId(req.getOrderId());
        updateOrder.setDiscountAuditUserId(req.getAuditUserId());
        updateOrder.setDiscountAuditUserName(personnel.getName());
        updateOrder.setDiscountApplyRemark(req.getRemark());
        updateOrder.setDiscountApplyTime(new Date());
        updateOrder.setDiscountAuditTime(null);
        updateOrder.updateById();
    }

    @Override
    public void discountApplyAudit(OrderDiscountApplyAuditDto req) {
        OrderExt order = queryById(req.getOrderId());
        if (order == null) {
            throw new BusinessEntityNotFoundException(req.getOrderId(), "订单");
        }
        if (order.getPaymentStatus() == PaymentStatusEnum.Complete) {
            throw new BusinessException("此订单已付完全款，不能再申请优惠。");
        }
        if (order.getAcceptStatus()) {
            throw new BusinessException("此订单已受理，不能再申请优惠 。");
        }
        if (!SecurityUtils.getUserContent().getId().equals(order.getDiscountAuditUserId())) {
            throw new BusinessException("你不是此订单的优惠审批人，不能进行此操作。");
        }

        for (OrderDiscountApplyItemDto item : req.getItems()) {
            OrderItem obj = orderItemMapper.selectById(item.getItemId());
            if (obj == null) {
                throw new BusinessEntityNotFoundException(item.getItemId(), "订单明细");
            }
            obj.setDiscountMoney(item.getDiscountMoney());
            obj.updateById();
        }

        Order updateOrder = new Order();
        updateOrder.setId(req.getOrderId());
        updateOrder.setDiscountAuditRemark(req.getRemark());
        updateOrder.setDiscountAuditStatus(req.getIsPass());
        updateOrder.setDiscountAuditTime(new Date());
        updateOrder.setDiscountAuditUserName(SecurityUtils.getUserContent().getPersonnelName());
        updateOrder.updateById();
    }


    @Override
    public IPage<OrderExt> queryPaymentTimeOut(int pageSize, int pageIndex) {
        Page<OrderExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<OrderExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderExt::getSubmitStatus, true);
        lq.eq(OrderExt::getAcceptStatus, false);
        lq.apply("real_min_money<=real_money");
        return orderExtMapper.selectPage(page, lq);
    }

    @Override
    public List<OrderAttr> queryAttrByItem(String itemId) {
        LambdaQueryWrapper<OrderAttr> lq = Wrappers.lambdaQuery();
        lq.eq(OrderAttr::getOrderItemId, itemId);
        return orderAttrMapper.selectList(lq);
    }

    @Override
    public List<OrderExt> queryExpire() {
        return orderExtMapper.queryExpire();
    }

    @Override
    public List<OrderItemByDefunct> queryItemByDefunct(String ids) {
        if (StringUtils.isNullOrEmpty(ids)) {
            return new ArrayList<>();
        }

        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderItemExt::getSubmitStatus, true);
        lq.in(OrderItemExt::getDefunctId, ids.split(","));
        lq.orderByDesc(OrderItemExt::getSubmitTime);
        return orderItemExtMapper.selectList(lq).stream().map((s -> {
            OrderItemByDefunct obj = new OrderItemByDefunct();
            obj.setSkuId(s.getSkuId());
            obj.setSkuNameAs(s.getNameAs());
            obj.setSaleAttrDesc(s.getSaleAttrDesc());
            obj.setCustName(s.getCustName());
            obj.setLinkmanPhone(s.getLinkmanPhone());
            obj.setOrderCode(s.getOrderCode());
            obj.setOrderTime(s.getSubmitTime());
            obj.setPersonnelId(s.getPersonnelId());
            obj.setPersonnelName(s.getPersonnelName());
            return obj;
        })).collect(Collectors.toList());
    }

    @Override
    public IPage<OrderReportExt> querySaleReport(String searchText, Date start, Date end, Integer pageSize, Integer pageIndex) {
//        Page<OrderReportExt> page = new Page<>(pageIndex, pageSize);
//        LambdaQueryWrapper<OrderReportExt> lq = Wrappers.lambdaQuery();
//        if (start != null) {
//            lq.gt(OrderReportExt::getSubmitTime, start);
//        }
//        if (end != null) {
//            lq.le(OrderReportExt::getSubmitTime, end);
//        }
//        if (!StringUtils.isNullOrEmpty(searchText)) {
//            lq.like(OrderReportExt::getPersonnelName, searchText).or().like(OrderReportExt::getDeptName, searchText).or().like(OrderReportExt::getNameAs, searchText);
//        }
//        return orderReportExtMapper.selectPage(page, lq);
        return null;
    }

    @Override
    public List<PersonnelDto> queryDiscountAuditPersonnel(String orderId, Double discountMoney) {
        OrderVo orderVo = queryById(orderId);
        if (!orderVo.getSubmitStatus()) {
            throw new BusinessException("订单没有提交。");
        }
        if (discountMoney <= 0) {
            throw new BusinessException("申请优惠金额不能等于或小于0.");
        }
        if (discountMoney > orderVo.getPlanMoney()) {
            throw new BusinessException("申请优惠金额不能大于订单金额。");
        }

        List<UserExt> users = new ArrayList<>();
        if (discountMoney / orderVo.getPlanMoney() <= Double.valueOf(configureService.getValueByCode(OrderConfigureCode.order_discount_apply_level_one))) {
            users.addAll(appPowerService.queryUserByResourcePower(OrderConfigureCode.order_discount_apply_level_one, PowerTypeEnum.Order_Discount_Apply));
        }
        if (discountMoney / orderVo.getPlanMoney() <= Double.valueOf(configureService.getValueByCode(OrderConfigureCode.order_discount_apply_level_two))) {
            users.addAll(appPowerService.queryUserByResourcePower(OrderConfigureCode.order_discount_apply_level_two, PowerTypeEnum.Order_Discount_Apply));
        }
        if (discountMoney / orderVo.getPlanMoney() <= Double.valueOf(configureService.getValueByCode(OrderConfigureCode.order_discount_apply_level_three))) {
            users.addAll(appPowerService.queryUserByResourcePower(OrderConfigureCode.order_discount_apply_level_three, PowerTypeEnum.Order_Discount_Apply));
        }
        if (discountMoney / orderVo.getPlanMoney() <= Double.valueOf(configureService.getValueByCode(OrderConfigureCode.order_discount_apply_level_four))) {
            users.addAll(appPowerService.queryUserByResourcePower(OrderConfigureCode.order_discount_apply_level_four, PowerTypeEnum.Order_Discount_Apply));
        }
        if (StringUtils.isNullOrEmpty(users)) {
            throw new BusinessException("当前没有配置优惠申请审批权限。");
        }

        return users.stream().map(s -> {
            PersonnelDto obj = new PersonnelDto();
            obj.setId(s.getPersonnelId());
            obj.setName(s.getPersonnelName());
            obj.setUserId(s.getId());
            return obj;

        }).collect(Collectors.toList());
    }

    @Override
    public List<PersonnelDto> queryExpireAuditPersonnel() {
        List<UserExt> users = appPowerService.queryUserByResourcePower(OrderConfigureCode.order_expire_apply_audit, PowerTypeEnum.Order_Discount_Apply);
        if (StringUtils.isNullOrEmpty(users)) {
            throw new BusinessException("当前没有设置审批人。");
        }
        return users.stream().map(s -> {
            PersonnelDto obj = new PersonnelDto();
            obj.setId(s.getPersonnelId());
            obj.setName(s.getPersonnelName());
            obj.setUserId(s.getId());
            return obj;

        }).collect(Collectors.toList());
    }

    @Override
    public PowerResourceSet queryResourcePower(String roleId, int pageIndex, int pageSize) {
        PowerResourceSet set = new PowerResourceSet("order_discount_audit_level", "订单优惠审批权限", PowerTypeEnum.Order_Discount_Apply);
        List<PowerResourceObject> list = new ArrayList<>();
        Double discount1 = configureService.getValueDoubleByCode(OrderConfigureCode.order_discount_apply_level_one);
        if (discount1 != null) {
            list.add(new PowerResourceObject(OrderConfigureCode.order_discount_apply_level_one, "level_1", "订单优惠一级审批权限", String.format("优惠审批上限 ≤ %.0f%%", discount1 * 100),
                    appPowerService.checkResourcePower(roleId, OrderConfigureCode.order_discount_apply_level_one, PowerTypeEnum.Order_Discount_Apply)));
        }

        Double discount2 = configureService.getValueDoubleByCode(OrderConfigureCode.order_discount_apply_level_two);
        if (discount2 != null) {
            list.add(new PowerResourceObject(OrderConfigureCode.order_discount_apply_level_two, "level_2", "订单优惠二级审批权限", String.format("优惠审批上限 ≤ %.0f%%", discount2 * 100),
                    appPowerService.checkResourcePower(roleId, OrderConfigureCode.order_discount_apply_level_two, PowerTypeEnum.Order_Discount_Apply)));
        }

        Double discount3 = configureService.getValueDoubleByCode(OrderConfigureCode.order_discount_apply_level_three);
        if (discount3 != null) {
            list.add(new PowerResourceObject(OrderConfigureCode.order_discount_apply_level_three, "level_3", "订单优惠三级审批权限", String.format("优惠审批上限 ≤ %.0f%%", discount3 * 100),
                    appPowerService.checkResourcePower(roleId, OrderConfigureCode.order_discount_apply_level_three, PowerTypeEnum.Order_Discount_Apply)));
        }

        Double discount4 = configureService.getValueDoubleByCode(OrderConfigureCode.order_discount_apply_level_four);
        if (discount4 != null) {
            list.add(new PowerResourceObject(OrderConfigureCode.order_discount_apply_level_four, "level_4", "订单优惠四级审批权限", String.format("优惠审批上限 ≤ %.0f%%", discount4 * 100),
                    appPowerService.checkResourcePower(roleId, OrderConfigureCode.order_discount_apply_level_four, PowerTypeEnum.Order_Discount_Apply)));
        }

        list.add(new PowerResourceObject(OrderConfigureCode.order_expire_apply_audit, "expire_apply", "订单延期审批", "订单到期未付款的延期申请审批",
                appPowerService.checkResourcePower(roleId, OrderConfigureCode.order_expire_apply_audit, PowerTypeEnum.Order_Discount_Apply)));

        set.setPageRecord(list);
        return set;
    }
}